1

什么是ES6模块?

在ES6中,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。在看到这里的时候感觉很熟悉,这不就是匿名函数自执行,然后一个个匿名函数放在一个个文件中的么,一个模块就是一个放在文件中的匿名自执行函数。两者对比就像下面这样:

// add.js 
(function(window){
    function add(a, b) {
       return a + b;
    }
    
    window.add = add // 通过window对象把 add 函数向外开放
})(window)

而使用ES6的模块, 就像下面

// add.js
function add(a, b) {
  return a + b;
}
export default add; // 通过export 导出 add方法

当然了,ES6的模块肯定是比匿名函数自执行更加高级的一种封装了。相比于匿名函数,ES6模块具有下面几种特点。

1. ES6默认使用严格模式, 而不需要使用 "use strict"
2. ES6模块是编译时加载,对代码进行静态分析
3. 对外抛出接口的时候,不会污染全局的对象
4. 能够有效的处理依赖, 而且只会在第一次加载模块时,代码运行一次。后面再次加载,不会重复 运行,会从缓存中读取

......暂时这些,以后待补充

至于为什么时候ES6的模块产生的历史就不讨论,网络上很多。个人感觉明白了它的历史就能更好的明白它的特性。

export 与 import

说到模块,就需要想到两点,一个是模块的对外接口,后面文章中使用导出来表示,另外一个是引入其他模块的接口,后面文章中使用导入来表示。

export命令用于规定模块的导出import命令用于模块的导入

重头戏就来了,怎么更好更快的理解模块的导出导入

当模块引入其他模块的时候,最终是获取其模块导出的值(基本数据类型或者引用类型)。于是可以这样去理解,当我们引入的模块(文件)已经确定下来了,那么导入的值也就确定下来。

// add.js
function add(a, b) {
   return a + b;
}
export default add

// main.js
import add from './add.js'
add(1,2) // 3 

上面导入的是 add.js 这个模块,其实主要是把add.js 中的 add 函数进行引入。

当需要到导入多个值的时候,可以通过对象来返回多个所需要的值。

// util.js
function add(a, b) {
   return a + b;
}

function reduce(a, b) {
   return a - b;
}
// 通过对象来返回多个值
export default {add: add, reduce: reduce};

// main.js
import util from './util.js'
console.log(util) // {add: add, reduce: reduce}

到这里,我个人觉得模块的导入导出基本上就已经很好了。因为这样不管是导出还是导入,对接的接口都是简单方便。

当然这只是我觉得。还是上面的例子

// util.js
function add(a, b) {
   return a + b;
}

function reduce(a, b) {
   return a - b;
}

export default {add: add, reduce: reduce, name: 'util'}

// main.js
import util from './util.js'

util.add(1, 2) // => 3

util.reduce(4, 3) // => 1

util.name // => 'util'

有人说,当导入的是值是对象的时候,需要多次去使用对象获取属性。 就像上面需要多次使用util去获取属性。ES6中不是有解构赋值么,用来处理对象多次获取属性的问题,那么导入对象的时候,也可以这样去处理。

于是按照对象的解构赋值,对上面的 main.js 改变。

// main.js
import {add: addFn} from './util.js'
// 这里在`webpack`中编译就已经报错了, ES6模块不支持这种方式

// 使用另外一种解构方式,`导出`模块的属性名与`导入`的变量名一致

// main.js
import { add } from './util.js'
console.log(add)  // undefined
// 这里在`webpack`编译中没有报出错误,但是还有警告: "export 'add' was not found  

// 于是对 util.js 的`导出`进行改变
//util.js
 function add(a, b) {
   return a + b;
}

function reduce(a, b) {
   return a - b;
}

export {add, reduce, name: 'util'}
// 当修改完util.js 就完成了util.js模块`导出` 与 main.js模块的`导入`对接

模块的导入导出大致可以分为两种模式

1. default 模式

default 模式下,模块中导出的值可以使用任何类型(不管是基本类型还是引用类型),都可以对外输出。而导入的此模块也是很简单,提供一个接收的变量就可以(推荐这种模式)
例子如下:

// util.js 
function add(a, b) {
  return a + b;
}
function reduce(a, b) {
  return a - b;
}

const obj = { add, reduce };

export default obj;
// main.js
import util from './util.js';
// util 是可以变换任意名称
console.log(util)// => {add: ƒ, reduce: ƒ}

2. { xxx } 模式

{ xxx } 是不需要在模块导出的时候使用default的。但是这种方式下,导出的值一定是object的。
导入的模块时是需要使用 { xxx }来接收。而且接收的变量名称还必须与导出模块属性名的一样。
例子如下:

// util.js 
function add(a, b) {
  return a + b;
}
function reduce(a, b) {
  return a - b;
}

let obj = { add, reduce };
// export obj; //webpack 编译报错

export { add, reduce }; 

// 除了这样直接导出对象,还可以像下面这样

export let name = 'util';
// 与 export { name } 效果一样;

深入了解的话,两者还是可以一起合用

function add(a, b) {
  return a + b;
}
function reduce(a, b) {
  return a - b;
}

export let name = 'util';
export { add, reduce };
// 相当于把这些属性合并在一起
// main.js
import { add, reduce, name } from './util.js' 
console.log(add) // add(a, b) { return a + b; }
console.log(name) // util 
as 重命名

as 重命名主要是用于 { xxx }模式。因为在导出的时候,属性名是被确定下来,而在导入此模块的时候,变量名需要跟此属性名一样才能获取对应的值。而使用 as 不仅能够帮助导出模块把属性名重命名,也能够帮导入模块把接收的变量名进行重命名。
例子如下:

// util.js
function add(a, b) {
    return a + b;
}

export { add as addFn};
// main.js
import { addFn as add } from './util.js'

console.log(add) // add(a, b) { return a + b; }

上面是个人关于ES6的模块个人理解和学习心得。

另外想要深入了解的可以查看官方文档 http://www.ecma-international...


火星田园犬
933 声望685 粉丝

小心驾驶, 专业埋雷